home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Cream of the Crop 1
/
Cream of the Crop 1.iso
/
UTILITY
/
SRDISK13.ARJ
/
SRDISK.C
< prev
next >
Wrap
C/C++ Source or Header
|
1992-01-18
|
39KB
|
1,331 lines
/*
** ReSizeable RAMDisk formatter
**
** Copyright (c) 1992 Marko Kohtala
**
** Some documentation and license available in accompanying file
** SRDISK.DOC. If not, contact author by sending E-mail from
**
** Internet, Bitnet etc. to 'Marko.Kohtala@hut.fi'
** CompuServe to '>INTERNET:Marko.Kohtala@hut.fi'
**
** or by calling Airline QBBS, 24H, HST, V.32, V.42, MNP,
** +358-0-8725380, and leaving mail to me, Marko Kohtala.
**
** In general, this is FREEWARE.
**
** To compile with Borland C++ 2.0: bcc -Z -O srdisk.c
** To compile with Borland C++ 3.0: bcc -O2 srdisk.c
**
*/
#define VERSION "1.30"
/* History
1.00 09-06-91 Initial release
1.10 06-09-91
- Added full support for multiple FATs. 1.00 had the /F switch, but no
support for it in formatter.
- Updated to IOCTL_msg versio 1.10 so that media byte is no longer used
to indicate the media change but to indicate the drive is RAM disk.
- Some minor fixes.
1.20 04-10-1991
- Fixed name of program by adding the missing 'Re' to 'Sizeable'.
- Added 16 bit FAT support; more 'sizeable' disks that had over 4077
clusters were not operational. Due to DOS's inconsistent behaviour,
disks with over 4077 and under 4088 clusters (or over 65518, possible
with 128 byte clusters and 8M disk size) are avoided by making
clusters bigger.
- Added DOS lookalike disk formats via switch /F.
- The FAT number is now defined via switch /A instead of /F.
- The time of format is stored in volume label.
- Upgraded to IOCTL_msg version 1.20 which tells the type of memory used
by the driver.
- Disallow sectors greater than 512 bytes as DOS can not handle them
properly but rather crashes when it encounters them.
- Allow clusters up to 8 kilobytes.
- Enhanced help.
1.30 18-01-1992
- Changed to freeware from public domain
- Changed the driver control from IOCTL calls to multiplex interrupt.
- Added support for over 32M RAM drives (up to 4096M). Over 32M drives
need DOS 4+ because they use over 0xFFFF sectors.
- Added /V switch for program verbosity control. /Y now only forces the
disk format, it does not make the program less verbose.
- Support for chained drivers. These drivers all contribute memory for
the same virtual drive. Added switch /M to control how much memory may
be used by each driver in the chain.
- Formatting reads the root directory to find out if there is anything
that would be destroyed. If not, it will not ask for permission to
destroy.
- Added /E switch to set environment variables SRDISKn to show srdisk
drives.
- Scans Drive Parameter Table on DOS 2 and 3 to find the drive letters,
if necessary.
*/
#include <assert.h>
#include <stdlib.h>
#include <stdio.h>
#include <io.h>
#include <dir.h>
#include <dos.h>
#include <string.h>
#include <time.h>
typedef unsigned char byte;
typedef unsigned short word;
typedef unsigned long dword;
/* Configuration structure internal to device driver (byte aligned) */
#pragma option -a-
#pragma pack(1)
struct dev_hdr {
struct dev_hdr far *next;
word attr;
word strategy;
word commands;
byte units;
union {
char volume[12]; /* Volume label combined of fields below */
struct {
char ID[3]; /* Identification string 'SRD' */
char memory[4]; /* Memory type string */
char version[4]; /* Device driver version string */
char null;
} s;
} u;
byte v_format; /* Config_s format version */
struct config_s near *conf; /* Offset to cofig_s */
};
struct config_s { /* The whole structure */
byte drive; /* Drive letter of this driver */
byte flags; /* Capability flags */
word (far *disk_IO)(void); /* Disk I/O routine entry */
dword (near *malloc_off)(dword _s); /* Memory allocation routine entry offset */
struct dev_hdr _seg *next; /* Next chained driver segment */
dword maxK; /* Maximum memory allowed for disk */
dword size; /* Current size in Kbytes */
dword sectors; /* Total sectors in this part of the disk */
word BPB_bps; /* BPB - bytes per sector */
/* The rest is removed from chained drivers, used only in the main driver */
byte BPB_spc; /* BPB - sectors per cluster */
word BPB_reserved; /* BPB - reserved sectors in the beginning */
byte BPB_FATs; /* BPB - number of FATs on disk */
word BPB_dir; /* BPB - root directory entries */
word BPB_sectors; /* BPB - sectors on disk (16-bit) */
byte BPB_media; /* BPB - identifies the media (default 0xFA) */
word BPB_FATsectors; /* BPB - sectors per FAT */
word BPB_spt; /* BPB - sectors per track (imaginary) */
word BPB_heads; /* BPB - heads (imaginary) */
dword BPB_hidden; /* BPB - hidden sectors */
dword BPB_tsectors; /* BPB - sectors on disk (32-bit) */
dword tsize; /* Total size for the disk */
byte RW_access; /* b0 = enable, b1 = write */
signed char media_change; /* -1 if media changed, 1 if not */
word open_files; /* Number of open files on disk */
struct dev_hdr _seg *next_drive; /* Segment of next SRDISK drive */
};
#pragma option -a
#pragma pack()
struct config_s far *mainconf, far *conf;
struct format { /* Disk format/configuration description */
byte RW_access; /* Read/write access flags */
int chain_len; /* Number of drivers chained to this drive */
dword max_size; /* Largest possible disk size (truth may be less) */
dword current_size; /* Counted current size from the driver chain */
dword size; /* Defined current size */
int bps; /* Bytes per sector */
int spc; /* Sectors per cluster */
int reserved; /* Reserved sectors in the beginning (boot) */
int FATs; /* Number of FAT copies */
int dir_entries; /* Directory entries in the root directory */
int spFAT; /* Sectors per FAT */
dword sectors; /* Total sectors on drive */
int FAT_sectors; /* Total FAT sectors */
int dir_sectors; /* Directory sectors */
int dir_start; /* First root directory sector */
int system_sectors; /* Boot, FAT and root dir sectors combined */
long data_sectors; /* Total number of usable data sectors */
int cluster_size; /* Size of one cluster in bytes */
dword clusters; /* Total number of clusters */
int FAT_type; /* Number of bits in one FAT entry (12 or 16) */
} f;
#define MULTIPLEXAH 0x72
#define V_FORMAT 0 /* config_s structure format version used here */
#define C_APPENDED 1 /* Capable of having appended drivers */
#define C_MULTIPLE 2 /* Capable of driving many disks */
#define C_32BITSEC 4 /* Capable of handling over 32-bit sector addresses */
#define C_UNKNOWN 0xF8
#define READ_ACCESS 1 /* Bit masks for RW_access in IOCTL_msg_s */
#define WRITE_ACCESS 2
int root_files = 1; /* Number of files in root directory */
/* Variables possibly supplied in command line */
int drive=0;
int format_f=0; /* Nonzero if new format given */
int force_f=0; /* Nonzero if ok to format */
int f_set_env=0; /* Set environment variables */
int verbose=-1; /* Verbose: 1 banner, */
/* 2 + new format, 3 + old format, 4 + long format */
enum {same, set, clear} write_f = same; /* Write protect flag */
long disk_size=-1; /* Size in kilobytes, -1 not set */
int sector_size=-1; /* Sector size, -1 not set */
int cluster_size=-1; /* Allocation unit size, -1 not set */
int dir_entries=-1; /* Directory entries in root directory, -1 not set */
int FATs=-1; /* FAT copies on the disk */
int media=-1; /* New media */
int sec_per_track=-1; /* Sectors per track */
int sides=-1; /* Sides on disk */
int maxKs=0; /* Top index in maxK[] */
struct { /* Maximum Kbytes for different drivers in chain */
dword size;
int set:1;
} maxK[10];
/*
** Declarations
*/
void print_format(void);
void retrieve_old_format(void);
char *stringisize_flags(int flags);
char *stringisize_memory(int mem);
struct config_s far *conf_ptr(struct dev_hdr _seg *dev);
/*
** SYNTAX
*/
void print_syntax(void)
{
fputs(
"\n"
"Syntax: SRDISK [<drive letter>[:]] [<size>] [/F:<DOS disk type>]\n"
"\t\t[/S:<sector size>] [/C:<cluster size>] [/D:<dir entries>]\n"
"\t\t[/A:<FAT copies>] [/M:<size>[:<size>[...]]] [/W[-]]\n"
"\t\t[/V:<verbose>] [/Y] [/E] [/?]\n\n"
"Anything inside [] is optional, the brackets must not be typed.\n"
"'<something>' must be replaced by what 'something' tells.\n\n"
"<drive letter> specifies the drive that is the RAM disk.\n"
"<size> determines the disk size in kilobytes.\n"
"/F:<DOS disk type> may be one of 160, 180, 320, 360, 720, 1200, 1440.\n"
"/S:<sector size> is a power of 2 in range from 128 to 512 bytes.\n"
"/C:<cluster size> is a power of 2 in range from 128 to 8192 bytes.\n"
"/D:<dir entries> is the maximum number of entries in the root directory.\n"
"/A:<FAT copies> number of File Allocation Tables on disk. 1 is enough.\n"
"/M List of max memory to allocate by each driver in driver chain\n"
"/W Write protect disk, /W- enables writes.\n"
"/V Verbose level from 1 (quiet) to 5 (verbose); default 2.\n"
"/E Set environment variables SRDISKn (n=1,2,...) to SRDISK drive letters.\n"
"/Y Yes, destroy the contents.\n"
"/? This help.\n"
, stderr);
}
/*
** ERROR HANDLING FUNCTIONS
*/
void syntax(char *err)
{
fprintf(stderr, "\nSyntax error: %s\n", err);
print_syntax();
exit(3);
}
void fatal(char *err)
{
fprintf(stderr, "\nFatal error: %s\n", err);
exit(1);
}
void error(char *err)
{
fprintf(stderr, "\nError: %s\n", err);
return;
}
void warning(char *err)
{
fprintf(stderr, "\nWarning: %s\n", err);
return;
}
/*
** COMMAND LINE PARSER
*/
long parse_narg(char *argp, char **next)
{
long res;
if (*argp == ':') argp++, (*next)++;
res = strtol(argp, next, 10);
if (argp == *next) return -1L;
return res;
}
int ispow2(int size)
{
int cmp;
for (cmp = 128; cmp; cmp <<=1)
if (cmp == size) return 1;
return 0;
}
void set_DOS_disk(int size)
{
static struct {
int disk_size;
int media;
int cluster_size;
int dir_entries;
int sec_per_track;
int sides;
} dos_disk[] = {
{ 160, 0xFE, 512, 64, 8, 1 },
{ 180, 0xFC, 512, 64, 9, 1 },
{ 320, 0xFF,1024, 112, 8, 2 },
{ 360, 0xFD,1024, 112, 9, 2 },
{ 720, 0xF9,1024, 112, 9, 2 },
{ 1200, 0xF9, 512, 224, 15, 2 },
{ 1440, 0xF0, 512, 224, 18, 2 },
{0}
};
int i;
for (i=0; dos_disk[i].disk_size; i++)
if (dos_disk[i].disk_size == size) {
disk_size = size;
cluster_size = dos_disk[i].cluster_size;
dir_entries = dos_disk[i].dir_entries;
media = dos_disk[i].media;
sec_per_track = dos_disk[i].sec_per_track;
sides = dos_disk[i].sides;
FATs = 2;
sector_size = 512;
format_f++;
return;
}
syntax("Unknown DOS disk size");
}
void parse_cmdline(int argc, char *argv[])
{
int arg;
char *argp;
for(arg=1; arg < argc; arg++) {
argp = argv[arg];
while(*argp) {
if (*argp == '/' || *argp == '-') {
argp++;
switch(toupper(*argp++)) {
case '?':
case 'H':
print_syntax();
exit(0);
case 'W':
switch(*argp) {
case '-': argp++;
write_f = clear;
break;
case '+': argp++;
default: write_f = set;
}
break;
case 'Y':
force_f++;
break;
case 'S': /* Sector size */
sector_size = parse_narg(argp, &argp);
if (!ispow2(sector_size) || sector_size > 512)
syntax("Invalid sector size");
format_f++;
break;
case 'C': /* Cluster size */
cluster_size = parse_narg(argp, &argp);
if (!ispow2(cluster_size) || cluster_size > 8192)
if (cluster_size % 128 || cluster_size < 128 || cluster_size > 8192)
syntax("Invalid cluster size");
format_f++;
break;
case 'D': /* Directory entries */
dir_entries = parse_narg(argp, &argp);
if (dir_entries < -1 || !dir_entries || dir_entries == 1
|| dir_entries > 1000)
syntax("Invalid number of directory entries");
format_f++;
break;
case 'A': /* FATs */
FATs = parse_narg(argp, &argp);
if (FATs < -1 || !FATs)
syntax("Invalid number of FAT copies");
format_f++;
break;
case 'F': /* DOS disk format */
disk_size = parse_narg(argp, &argp);
set_DOS_disk(disk_size);
break;
case 'V': /* Verbose level */
verbose = parse_narg(argp, &argp);
if (verbose < 1 || verbose > 5)
syntax("Invalid verbose level");
break;
case 'M': /* MaxK for different partitions */
maxKs = 0;
memset(maxK, 0, sizeof maxK);
do {
dword size;
if (maxKs == sizeof maxK / sizeof maxK[0])
syntax("Too many /M values");
size = parse_narg(argp, &argp);
if (size > 0x3FFFFFL)
syntax("Too large partition size");
if (size != -1L) {
maxK[maxKs].size = size;
maxK[maxKs].set = 1;
}
maxKs++;
} while(*argp == ':');
break;
case 'E': /* Set environment variables to show SRDISKs */
f_set_env = 1;
break;
default:
syntax("Unknown switch");
}
}
else {
if (*argp == ' ' || *argp == '\t') argp++;
else if (isdigit(*argp)) {
disk_size = strtol(argp, &argp, 10);
if (disk_size < 0 || disk_size > 0x3FFFFFL)
syntax("Invalid disk size");
format_f++;
}
else {
if (drive) syntax("Unrecognised character on command line");
drive = toupper(*argp++)-'A'+1;
if (drive < 1 || drive > 'Z'-'A'+1) syntax("Invalid drive");
if (*argp == ':') argp++;
}
}
}
}
}
/*
** Local allocation routine with error check
*/
void *xalloc(size_t s)
{
void *b = malloc(s);
if (!s) fatal("malloc() failed");
return b;
}
/*
** Get Y/N response
*/
int getYN(void)
{
int reply;
if (force_f) reply = 'Y';
else {
do reply = toupper(getch());
while (reply != 'Y' && reply != 'N');
}
printf("%c\n", reply);
if (reply == 'N') return 0;
return 1;
}
/*
** DOS time format conversions
*/
dword DOS_time(time_t time)
{
struct tm *ltime;
union {
struct {
word sec2 : 5,
min : 6,
hour : 5;
word day : 5,
month : 4,
year : 7;
} f;
dword l;
} file_time;
ltime = localtime(&time);
file_time.f.sec2 = ltime->tm_sec;
file_time.f.min = ltime->tm_min;
file_time.f.hour = ltime->tm_hour;
file_time.f.day = ltime->tm_mday;
file_time.f.month = ltime->tm_mon + 1;
file_time.f.year = ltime->tm_year - 80;
return file_time.l;
}
/*
** Read/Write sector from/to disk
**
** Return 0 for failure, transferred sector count otherwise
*/
int xfer_sector(char rw, int count, dword start, void *buffer)
{
struct config_s far *subconf = conf;
assert(count == 1); /* We currently support only 1 sector xfers */
while(subconf->sectors <= start) {
start -= subconf->sectors;
if ( ! (subconf = conf_ptr(subconf->next)) ) return 0;
}
/* !!!! Since count is always 1 here, we do not check if the transfer
continues into the next driver */
_ES = FP_SEG(buffer); /* <- This messes up the _AX */
_DI = FP_OFF(buffer);
_BH = rw;
_CX = count;
_DX = start >> 16;
_AX = start;
asm {
push ds
lds si,subconf
call dword ptr [si+2] /* !!!! Configuration format dependent */
pop ds
}
return _AX;
}
/*
** Read sector from disk
**
** Return 0 for failure, transferred sector count otherwise
*/
int read_sector(int count, dword start, void *buffer)
{
return xfer_sector(0, count, start, buffer);
}
/*
** Write sector to disk
**
** Return 0 for failure, transferred sector count otherwise
*/
int write_sector(int count, dword start, void *buffer)
{
return xfer_sector(1, count, start, buffer);
}
/*
** Count the files in root directory
*/
int count_root(void)
{
byte *sp;
int si;
dword sector = f.dir_start;
int entries = f.dir_entries;
int files = 0;
sp = xalloc(f.bps);
while(entries) {
read_sector(1, sector, sp);
for(si = 0; si < f.bps && entries; si += 32) {
if (sp[si] == 0) goto end; /* Unused, end of directory */
if (sp[si] != 0xE5 /* Not deleted */
&& !(sp[si+11] & 8)) /* and not label */
files++; /* so it is a file (or directory) */
entries--;
}
sector++;
}
end:
free(sp);
return files;
}
/*
** INITIALIZE DRIVE
*/
struct config_s far *conf_ptr(struct dev_hdr _seg *dev)
{
struct config_s far *conf;
if (!dev) return (void far *)NULL;
conf = MK_FP(dev, dev->conf);
if (dev->u.s.ID[0] != 'S'
|| dev->u.s.ID[1] != 'R'
|| dev->u.s.ID[2] != 'D'
|| dev->v_format != V_FORMAT
|| (conf->drive != '$' && (conf->drive < 'A' || conf->drive > 'Z'))
|| !conf->disk_IO
|| !conf->malloc_off)
fatal("SRDISK devices' internal tables are messed up!");
return conf;
}
void resolve_drive(struct config_s far *conf)
{
#pragma option -a-
/* This is drive parameter block for DOS versions 2-3.x */
struct dpb_s {
byte drive; /* drive number (00h = A:, 01h = B:, etc) */
byte unit; /* unit number within device driver */
word bps; /* bytes per sector */
byte hsnwc; /* highest sector number within a cluster */
byte c2sshift; /* shift count to convert clusters into sectors */
word ress; /* number of reserved sectors at beginning of drive */
byte FATs; /* number of FATs */
word dir; /* number of root directory entries */
word data; /* number of first sector containing user data */
word clusters; /* highest cluster number (number of data clusters + 1) */
byte spf; /* number of sectors per FAT */
word fdirs; /* sector number of first directory sector */
/* address of device driver header */
struct config_s far *device;
byte media; /* media ID byte */
byte used; /* 00h if disk accessed, FFh if not */
/* pointer to next DPB */
struct dpb_s far *next;
} far *dbp;
/* DOS 4+ uses different Drive Parameter Block and they should have
told the drive letters at device initialization anyway.
*/
if (_osmajor < 4) {
asm {
mov ah,0x52 /* SYSVARS call */
int 0x21 /* Call DOS */
mov ax,es:[bx]
mov dx,es:[bx+2]
mov word ptr dbp,ax
mov word ptr dbp+2,dx
}
do {
if ( dbp->device == MK_FP(FP_SEG(conf), 0) ) {
conf->drive = dbp->drive + 'A';
return;
}
dbp = dbp->next;
} while ( FP_OFF(dbp) != 0xFFFF && dbp ); /* && dbp just for luck */
}
fatal("SRDISK drive not in DOS Drive Parameter Block chain");
}
void init_drive(void)
{
struct dev_hdr _seg *dev;
_BX = _CX = _DX = 0;
_AX = MULTIPLEXAH << 8;
asm int 0x2F;
dev = (struct dev_hdr _seg *)_ES;
if (!dev
|| dev->u.s.ID[0] != 'S'
|| dev->u.s.ID[1] != 'R'
|| dev->u.s.ID[2] != 'D')
{
fatal("No SRDISK driver found");
}
else if (dev->v_format != V_FORMAT) {
fatal("Invalid SRDISK driver version");
}
conf = mainconf = conf_ptr(dev);
/* Check if driver does not know yet what drive it is */
do {
if ( conf->drive == '$' ) {
resolve_drive(conf);
}
} while ( conf = conf_ptr(conf->next_drive) );
conf = mainconf;
if (drive)
while(conf->drive != drive-1+'A') {
if ( ! (conf = conf_ptr(conf->next_drive)) )
fatal("Drive not ReSizeable RAMDisk");
}
else drive = conf->drive-'A'+1;
retrieve_old_format(); /* Setup f */
if (verbose > 3) print_format();
if (verbose > 4) {
struct config_s far *subconf = conf;
int part = 1;
for( ; subconf; subconf = conf_ptr(subconf->next), part++) {
printf("Driver %d of %d\n"
" Version %.4Fs\n"
" Memory: %.4Fs\n"
" Flags:%s\n"
" Max size: %luK\n"
" Size: %luK\n"
" Sectors: %lu\n\n"
,part, f.chain_len
,((struct dev_hdr _seg *)FP_SEG(subconf))->u.s.version
,((struct dev_hdr _seg *)FP_SEG(subconf))->u.s.memory
,stringisize_flags(subconf->flags)
,subconf->maxK
,subconf->size
,subconf->sectors
);
}
}
}
/*
** SET MAX KBYTES FOR DRIVERS IN CHAIN
*/
void setmaxK(void)
{
struct config_s far *subconf;
int i = 0;
if (maxKs > f.chain_len) {
error("Too many /M values");
return;
}
for (subconf = conf;
subconf && i < maxKs;
subconf = conf_ptr(subconf->next), i++)
{
if (maxK[i].set) subconf->maxK = maxK[i].size;
}
f.max_size = 0;
for (subconf = conf; subconf; subconf = conf_ptr(subconf->next) ) {
f.max_size += subconf->maxK;
}
if (verbose > 1) {
printf("\nAdjusted max allocation sizes");
if (!format_f) printf(" - reformat disk to enable change");
puts("");
}
}
/*
** SET WRITE PROTECT
*/
void set_write_protect()
{
switch(write_f) {
case set:
conf->RW_access &= ~WRITE_ACCESS;
if (verbose > 1)
printf("\nWrite protect enabled\n");
break;
case clear:
conf->RW_access |= WRITE_ACCESS;
if (verbose > 1)
printf("\nWrite protect disabled\n");
break;
}
}
/*
** FORMAT DISK
*/
int licence_to_kill(void)
{
if (!force_f && root_files) {
int reply;
printf("\n\aAbout to destroy all files on drive %c!\n\a"
"Continue (Y/N) ? ", drive-1+'A');
if (!getYN()) {
printf("\nOperation aborted\n");
return 0;
}
}
return 1;
}
/*
** Format printing
*/
char *stringisize_flags(int flags)
{
static char _string[60];
_string[0] = 0;
if (flags & C_APPENDED) strcat(_string, " APPENDED");
if (flags & C_MULTIPLE) strcat(_string, " MULTIPLE");
if (flags & C_32BITSEC) strcat(_string, " 32BITSEC");
if (flags & C_UNKNOWN) strcat(_string, " unknown");
return _string;
}
void print_format(void)
{
printf("\n"
"Drive %c:\n"
" Disk size: %luK\n"
" Cluster size: %d bytes\n"
" Sector size: %d bytes\n"
" Directory entries: %d\n"
" FAT copies: %d\n"
" Bytes available: %ld\n"
" Write protection: %s\n"
,drive-1+'A'
,f.size
,f.cluster_size
,f.bps
,f.dir_entries
,f.FATs
,f.clusters*f.cluster_size
,((f.RW_access & WRITE_ACCESS) ? "OFF" : "ON")
);
if (verbose > 3)
printf(" Sectors: %lu\n"
" Reserved sectors: %d\n"
" FAT sectors: %d\n"
" Directory sectors: %d\n"
" Sectors per cluster: %d\n"
" Clusters: %lu\n"
" FAT type: %u bit\n"
" Max size: %luK\n"
,f.sectors
,f.reserved
,f.FAT_sectors
,f.dir_sectors
,f.spc
,f.clusters
,f.FAT_type
,f.max_size
);
}
/*
** RETRIEVE OLD FORMAT FOR DISK
*/
void retrieve_old_format(void)
{
struct config_s far *subconf;
memset(&f, 0, sizeof f);
/* Scan the chain of drivers linked to the same drive */
for (subconf = conf; subconf; subconf = conf_ptr(subconf->next)) {
/* Make sure f.max_size does not overflow */
if (f.max_size && -f.max_size <= subconf->maxK)
f.max_size = -1;
else
f.max_size += subconf->maxK;
f.current_size += subconf->size;
f.chain_len++;
}
f.RW_access = conf->RW_access;
f.size = conf->tsize;
f.bps = conf->BPB_bps;
f.spc = conf->BPB_spc;
f.reserved = conf->BPB_reserved;
f.FATs = conf->BPB_FATs;
f.dir_entries = conf->BPB_dir;
f.spFAT = conf->BPB_FATsectors;
f.sectors = conf->BPB_tsectors;
f.FAT_sectors = f.spFAT * f.FATs;
f.dir_sectors = f.dir_entries * 32 / f.bps;
f.dir_start = f.reserved + f.FAT_sectors;
f.system_sectors = f.dir_start + f.dir_sectors;
f.cluster_size = f.spc * f.bps;
if (f.size) {
f.data_sectors = f.sectors - f.system_sectors;
f.clusters = f.data_sectors / f.spc;
}
f.FAT_type = f.clusters > 4086 ? 16 : 12;
if (sec_per_track == -1) sec_per_track = conf->BPB_spt;
if (sides == -1) sides = conf->BPB_heads;
}
/*
** COUNT FORMAT FOR DISK
**
** Return 0 if format is impossible
*/
int count_new_format(psize, pcluster_size, psector_size, pdir_entries, pFATs)
long psize;
int pcluster_size, psector_size, pdir_entries, pFATs;
{
f.FAT_type = 12; /* By default try to use 12 bit FAT */
f.size = psize;
f.cluster_size = pcluster_size;
f.bps = psector_size;
f.dir_entries = pdir_entries;
f.FATs = pFATs;
/* Make sure sectors are big enough for the disk */
while((f.sectors = f.size * 1024 / f.bps) >
((conf->flags & C_32BITSEC) ? 0x7FFFFF : 0xFFFFL) )
f.bps <<= 1;
if (f.bps > 512)
warning("Sector size larger than 512 bytes, may crash DOS");
if (f.cluster_size < f.bps)
f.cluster_size = f.bps;
{ div_t divr;
divr = div(f.dir_entries * 32, f.bps);
f.dir_sectors = divr.quot + (divr.rem ? 1 : 0);
}
count_clusters:
f.system_sectors = f.reserved + f.dir_sectors;
f.data_sectors = max(f.sectors - f.system_sectors, 0);
f.spc = f.cluster_size / f.bps;
{ ldiv_t divr;
divr = ldiv(((long)f.data_sectors + 2 * f.spc) * f.FAT_type,
(long)8 * f.cluster_size + f.FATs * f.FAT_type);
f.spFAT = divr.quot + (divr.rem ? 1 : 0);
}
f.FAT_sectors = f.spFAT * f.FATs;
f.system_sectors += f.FAT_sectors;
f.data_sectors = max(f.data_sectors - f.FAT_sectors, 0);
f.clusters = f.data_sectors / f.spc;
/* Make sure we use the right FAT type */
if (f.FAT_type < 16 && f.clusters > 4077) {
f.FAT_type = 16;
goto count_clusters;
}
if (f.FAT_type > 12 && f.clusters < 4088 || f.clusters > 65518) {
f.FAT_type = 12;
f.cluster_size <<= 1;
goto count_clusters;
}
f.dir_start = f.reserved + f.FAT_sectors;
/* If Disk will be disabled */
if (!f.size) {
f.data_sectors = 0;
f.clusters = 0;
return 1;
}
if (f.sectors <= f.system_sectors || !f.clusters)
return 0;
return 1;
}
/*
** CONFIGURE DRIVE FOR FORMAT f
**
** Disable drive and configure it. RW_access must be set by caller.
**
** Return 0 if format is impossible
*/
int configure_drive(void)
{
long Kleft = f.size;
struct config_s far *subconf;
dword alloc, lastalloc;
int err = 0;
dword (far *dmalloc)(dword); /* Make here the pointer to driver's malloc */
int old_access = conf->RW_access;
conf->RW_access = 0; /* Disable DOS access to drive */
if (f.size != f.current_size) {
for(subconf = conf; subconf; subconf = conf_ptr(subconf->next)) {
alloc = max(min(subconf->maxK, Kleft), 0);
dmalloc = MK_FP(FP_SEG(subconf), subconf->malloc_off);
lastalloc = dmalloc(alloc);
if (lastalloc != alloc && (err = !lastalloc) != 0) break;
subconf->size = lastalloc;
subconf->sectors = (long)lastalloc * 1024 / f.bps;
Kleft -= lastalloc;
}
if (Kleft > 0) { /* If not enough memory could be allocated */
err = 1;
if (!conf->next) { /* If single drive, try to preserve it */
/* If single drive, dmalloc is still valid */
if (dmalloc(f.current_size) == f.current_size) { /* Make it the old size */
conf->size = f.current_size; /* Fix back what was changed */
conf->sectors = (long)f.current_size * 1024 / f.bps;
conf->RW_access = old_access; /* Enable the disk */
error("Failed to allocate memory");
return 0; /* Return failure */
}
}
/* Free all memory */
for (subconf = conf; subconf; subconf = conf_ptr(subconf->next)) {
dmalloc = MK_FP(FP_SEG(subconf), subconf->malloc_off);
if (!dmalloc(0)) {
subconf->size = 0;
subconf->sectors = 0;
}
}
f.size = 0;
f.sectors = 0;
error("Failed to allocate memory - disk disabled");
}
if (Kleft < 0 && verbose > 1)
printf("\n%ldKbytes extra allocated,\n"
"Perhaps you should make your disk that much larger.\n"
,-Kleft);
}
for(subconf = conf; subconf; subconf = conf_ptr(subconf->next))
subconf->BPB_bps = f.bps;
conf->BPB_spc = f.spc;
conf->BPB_reserved = f.reserved;
conf->BPB_FATs = f.FATs;
conf->BPB_dir = f.dir_entries;
conf->BPB_sectors = (conf->flags & C_32BITSEC && f.sectors > 0xFFFEL) ?
0 : f.sectors;
conf->BPB_media = media == -1 ? 0xFA : media;
conf->BPB_FATsectors = f.spFAT;
conf->BPB_spt = sec_per_track;
conf->BPB_heads = sides;
conf->BPB_hidden = 0L;
conf->BPB_tsectors = f.sectors;
conf->tsize = f.size;
conf->open_files = 0;
if (format_f) conf->media_change = -1;
return !err;
}
void format_disk(void)
{
long old_disk_size = f.size;
ldiv_t ldivr;
int Fsec;
int i;
byte *sector;
if (disk_size == -1) disk_size = conf->size;
if (disk_size > f.max_size) {
error("Not enough memory for disk available");
return;
}
if (!force_f && conf->open_files) {
error("Files open on drive");
return;
}
/* Count root files before f is messed by count_new_format() */
root_files = count_root();
if (!count_new_format(disk_size,
cluster_size == -1 ? conf->BPB_bps * conf->BPB_spc
: cluster_size,
sector_size == -1 ? conf->BPB_bps : sector_size,
dir_entries == -1 ? conf->BPB_dir : dir_entries,
FATs == -1 ? conf->BPB_FATs : FATs))
{
error("Impossible format for disk");
return;
}
/* If Disk will be disabled */
if (!f.size) {
if (!old_disk_size) {
/* If was disabled also before */
configure_drive();
if (verbose > 1) printf("\nNew configuration saved for later use\n");
} else {
/* If disk now get's disabled */
if (!licence_to_kill()) return;
configure_drive();
if (verbose > 1) printf("\nRAMDisk disabled\n");
}
return;
}
if (verbose > 1) {
printf("\nNew disk configuration:\n");
print_format();
}
if (old_disk_size && !licence_to_kill()) return;
/* Request the new disk space and configure the driver(s) */
if (!configure_drive()) return;
sector = xalloc(f.bps);
/* Write the new disk */
/* Make the boot sector */
memset(sector, 0, f.bps);
*(word *)sector = 0x3CEB; /* Boot record JMP instruction */
*(byte *)(sector+2) = 0x90; /* NOP instruction */
memcpy(sector+3, "SRD "VERSION, 8); /* OEM code and version */
*(word *)(sector+11) = f.bps;
*(byte *)(sector+13) = f.spc;
*(word *)(sector+14) = f.reserved;
*(byte *)(sector+16) = f.FATs;
*(word *)(sector+17) = f.dir_entries;
*(word *)(sector+19) = conf->BPB_sectors;/* Sectors (16-bit) */
*(byte *)(sector+21) = conf->BPB_media; /* Media */
*(word *)(sector+22) = f.spFAT;
*(word *)(sector+24) = sec_per_track; /* Sectors per track */
*(word *)(sector+26) = sides; /* Sides */
*(dword *)(sector+28) = 0; /* Hidden sectors */
*(dword *)(sector+32) = f.sectors; /* Total number of sectors */
*(byte *)(sector+36) = -1; /* Physical drive number */
*(byte *)(sector+37) = 0; /* reserved */
*(byte *)(sector+38) = 0x29; /* Signature byte */
*(dword *)(sector+39) = time(NULL); /* Serial number */
_fmemcpy(sector+43,
((struct dev_hdr far *)MK_FP(FP_SEG(conf), 0))->u.volume,
11); /* Volume label */
memcpy(sector+54, f.FAT_type == 12 ? "FAT12 " :
f.FAT_type == 16 ? "FAT16 " : " "
,8);
*(word *)(sector+62) = 0xFEEB; /* Boot code (JMP $) */
*(word *)(sector+f.bps-2) = 0xAA55; /* Validity code */
write_sector(1, 0, sector); /* Write boot sector */
for (i = 0; i < f.FATs; i++) {
word sector_n =
f.reserved + f.spFAT * i;
/* Write 1st FAT sector */
memset(sector, 0, f.bps); /* Make 1st FAT sector */
((dword *)sector)[0] =
(f.FAT_type == 12 ? 0xFFFF00L : 0xFFFFFF00L) | conf->BPB_media;
write_sector(1, sector_n++, sector);
/* Write FAT sectors from 2nd to last */
((dword *)sector)[0] = 0L;
for (Fsec = 1; Fsec < f.spFAT; Fsec++)
write_sector(1, sector_n++, sector);
}
/* Write 1st directory sector */
f.dir_start = f.reserved + f.FAT_sectors;
_fmemcpy(sector, ((struct dev_hdr far *)MK_FP(FP_SEG(conf), 0))->u.volume, 11);
sector[11] = FA_LABEL;
*(dword *)(sector+22) = DOS_time(time(NULL));
write_sector(1, f.dir_start, sector);
/* Write directory sectors from 2nd to last */
memset(sector, 0, 16);
for (Fsec = 1; Fsec < f.dir_sectors; Fsec++)
write_sector(1, f.dir_start+Fsec, sector);
conf->RW_access = READ_ACCESS | (write_f == set ? 0 : WRITE_ACCESS);
free(sector);
if (verbose > 1) printf("\nDisk formatted\n");
}
/*
** Main environment setting
*/
/*
envptr - returns pointer to parent command.com's copy of the environment
Provided by Doug Dougherty, original source by S. Palmer.
*/
char far *
envptr(size)
int *size;
{
int parent_p;
/* memory control block */
#pragma option -a-
struct MCB {
char id;
unsigned int owner;
unsigned int size;
} far *mcb;
#pragma option -a
parent_p=peek(_psp,0x16); /* find pointer to parent in psp */
if (peek(parent_p,0x2c)==0) {
mcb = (struct MCB far *) (((long) (peek(parent_p-1,0x3) + parent_p)) << 16);
}
else {
mcb = (struct MCB far *) (((long) (peek(parent_p,0x2c) - 1)) << 16);
}
*size = mcb->size * 16;
return (char far *)MK_FP(FP_SEG(mcb) + 1, 0);
}
/*
msetenv - place an environment variable in command.com's copy of
the envrionment.
Provided by Doug Dougherty, original source by S. Palmer.
*/
int
msetenv(var,value)
char *var, *value;
{
char far *env1, far *env2;
char far *cp;
int size;
int l;
env1 = env2 = envptr(&size);
l = strlen(var);
strupr(var);
/*
Delete any existing variable with the name (var).
*/
while (*env2) {
if ((_fstrncmp(var,env2,l) == 0) && (env2[l] == '=')) {
cp = env2 + _fstrlen(env2) + 1;
_fmemcpy(env2,cp,size-(cp-env1));
}
else {
env2 += _fstrlen(env2) + 1;
}
}
/*
If the variable fits, shovel it in at the end of the envrionment.
*/
if (_fstrlen(value) && (size-(env2-env1)) >= (l + _fstrlen(value) + 3)) {
_fstrcpy(env2,var);
_fstrcat(env2,"=");
_fstrcat(env2,value);
env2[_fstrlen(env2)+1] = 0;
return(0);
}
/*
Return error indication if variable did not fit.
*/
return(-1);
}
void set_env()
{
struct config_s far *conf = mainconf;
char var[] = "SRDISK1";
char drive[] = "A";
if (verbose > 1) puts("");
do {
drive[0] = conf->drive;
if (verbose > 1) printf("Set %s=%s\n", var, drive);
if (msetenv(var, drive))
fatal("Not enough environment space");
var[6]++;
} while ( conf = conf_ptr(conf->next_drive) );
}
/*
** MAIN FUNCTION
*/
int main(int argc, char *argv[])
{
printf("ReSizeable RAMDisk Formatter version "VERSION". "
"Copyright (c) 1992 Marko Kohtala.\n");
if (argc > 1) parse_cmdline(argc, argv);
else if (verbose > 1) printf("\nFor help type 'SRDISK /?'.\n");
if (verbose == -1) verbose = 2;
init_drive(); /* Get pointer to driver configuration */
if (f_set_env) set_env();
if (maxKs) setmaxK();
if (format_f) format_disk();
else if (write_f != same) set_write_protect();
else if (!f_set_env && verbose < 4 && verbose > 1) {
if (f.size) print_format();
else printf("\nDrive %c: disabled\n", drive-1+'A');
}
return 0;
}